package org.pz.config;

import lombok.extern.slf4j.Slf4j;
import org.pz.handler.*;
import org.pz.filter.MallFilterSecurityInterceptor;
import org.pz.filter.RestfulUsernamePasswordAuthenticationFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.HttpStatusEntryPoint;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.savedrequest.NullRequestCache;

@Configuration
@Slf4j
public class SecurityWebConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private LoginSuccessHandler loginSuccessHandler;

    @Autowired
    private LoginFailureHandler loginFailureHandler;

    @Autowired
    private CLogoutSuccessHandler cLogoutSuccessHandler;

    @Autowired
    private MallSecurityMetadataSource mallSecurityMetadataSource;

    @Autowired
    private MallAccessDecisionManager mallAccessDecisionManager;

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        //登录信息
        http.formLogin()
                .disable() //禁止表单登录，如果前后端不分离，应该用这种表单登录吧
                //自定义登录页面，如果没有认证，会重定向到这里
                //.loginPage("http://localhost:4200/") //登录页面
                //.loginProcessingUrl("/login/in");  //登录路径，表单向该路径提交，应该跟 action 有关
                //.successHandler(loginSuccessHandler)  //认证成功后的处理器
                //.successForwardUrl("/login/getInfo")  //认证成功后的页面跳转
                //.failureHandler(loginFailureHandler)  //认证失败的处理器，有 failureForwardUrl 没有执行，不知道为啥，不管
                //.failureForwardUrl("/login/failure") //认证失败后页面跳转

                //退出信息
                //.and()
                .logout()
                //.logoutUrl() //退出登录路径，不写的话貌似就是 /logout，应该用不着
                .logoutSuccessHandler(cLogoutSuccessHandler)  //退出成功的处理器，貌似 handler 类的设置了，对应的跳转 url 就不起作用了
                //.logoutSuccessUrl("http://localhost:4200/")   //退出成功跳转的页面
                .clearAuthentication(true)   //清除 authentication 对象
                .invalidateHttpSession(true) //销毁 httpSession 对象
                //.deleteCookies("") //删除 cookie

                //添加认证过滤器
                .and()
                .addFilterAt(restfulUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)

                //访问是否需要认证
                .authorizeRequests()
                //.antMatchers("/login/**").permitAll()  //login 开头的资源不用认证
                .anyRequest().authenticated()//所有请求都需要认证
                //.and()
                //.anonymous().disable() //匿名用户禁止访问

                //添加授权过滤器
                .and()
                .addFilterAt(restfulFilterSecurityInterceptor(), FilterSecurityInterceptor.class)

                //发生异常的情况
                .exceptionHandling()
                //对应权限不足，403 的问题
                .accessDeniedHandler(new MallAccessDeniedHandler())
                //用于处理未认证的访问请求 401
                .authenticationEntryPoint(new MallStatusEntryPoint())
                //权限不足的页面
                //.accessDeniedPage("/default/notFound")

                .and()
                .requestCache().requestCache(new NullRequestCache())

                //关闭 csrf 防护
                .and()
                .csrf().disable();
    }

    /**
     * 认证过滤器
     * */
    public UsernamePasswordAuthenticationFilter restfulUsernamePasswordAuthenticationFilter() throws Exception {
        log.info("认证流程第一步：初始化 UsernamePasswordAuthenticationFilter");
        //1. 实例化自定义的认证过滤器
        UsernamePasswordAuthenticationFilter filter = new RestfulUsernamePasswordAuthenticationFilter();
        //2. 设置认证管理器
        filter.setAuthenticationManager(authenticationManager());
        //3. 认证成功的后置处理
        filter.setAuthenticationSuccessHandler(loginSuccessHandler);
        //4. 认证失败的后置处理器
        filter.setAuthenticationFailureHandler(loginFailureHandler);
        return filter;
    }

    /**
     * 授权过滤器
     * */
    public FilterSecurityInterceptor restfulFilterSecurityInterceptor(){
        MallFilterSecurityInterceptor fsi = new MallFilterSecurityInterceptor();
        fsi.setSecurityMetadataSource(mallSecurityMetadataSource);
        fsi.setAccessDecisionManager(mallAccessDecisionManager);
        return fsi;
    }

}
